package model;

import constant.Constants;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReadWriteLock;

public class BettingOffer {
    // 投注ID
    private int betOfferId;
    // 用于存储按投注金额排序的用户ID。键是投注金额，值是用户ID, TreeMap 按投注金额降序排序
    private TreeMap<Integer, Set<Integer>> stakes = new TreeMap<>(Comparator.reverseOrder());
    // 用于存储用户ID到其投注金额的映射，以便快速查找和更新用户的具体投注信息
    private ConcurrentHashMap<Integer, Integer> customerIdToStake = new ConcurrentHashMap<>();
    // 读写锁
    private final ReadWriteLock lock = new ReentrantReadWriteLock();

    public BettingOffer(int betOfferId) {
        this.betOfferId = betOfferId;
    }

    public int getBetOfferId() {
        return betOfferId;
    }

    /**
     * 更新或添加客户的投注金额
     * @param customerId 用户ID
     * @param stake 投注金额
     */
    public void updateStake(int customerId, int stake) {
        lock.writeLock().lock();
        try {
            // 更新或添加投注金额
            int previousStake = customerIdToStake.getOrDefault(customerId, 0);
            int newStake = previousStake + stake;
            customerIdToStake.put(customerId, newStake);

            // 从旧的投注金额中移除该用户
            if (previousStake > 0) {
                stakes.get(previousStake).remove(customerId);
                if (stakes.get(previousStake).isEmpty()) {
                    stakes.remove(previousStake);
                }
            }

            // 将用户添加到新的投注金额中
            stakes.computeIfAbsent(newStake, k -> new HashSet<>()).add(customerId);

            // 保持最多20个元素
            while (stakes.size() > Constants.COUNT_LIMIT) {
                Map.Entry<Integer, Set<Integer>> lastEntry = stakes.lastEntry();
                stakes.remove(lastEntry.getKey());
            }
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * 获取前20个最高投注金额的用户ID及其投注金额的映射
     * @return 前20个最高投注金额的用户ID及其投注金额的映射
     */
    public Map<Integer, Integer> getTop20Stakes() {
        lock.readLock().lock();
        try {
            Map<Integer, Integer> result = new LinkedHashMap<>();
            for (Map.Entry<Integer, Set<Integer>> entry : stakes.entrySet()) {
                for (int customerId : entry.getValue()) {
                    result.put(customerId, entry.getKey());
                    if (result.size() == Constants.COUNT_LIMIT) {
                        break;
                    }
                }
                if (result.size() == Constants.COUNT_LIMIT) {
                    break;
                }
            }
            return result;
        } finally {
            lock.readLock().unlock();
        }
    }
}